<?php

namespace App\Libs\TikTokSDK;

class TikTokClient
{
    public $appkey;

    public $secretKey;

    public $gatewayUrl;

    public $connectTimeout = 30;//30秒

    public $readTimeout = 80;//80秒

    protected $signMethod = "sha256";

    protected $sdkVersion = "lazop-sdk-php-20180422";

    public $logLevel;

    public function getAppkey()
    {
        return $this->appkey;
    }

    public function __construct($url = "", $appkey = "", $secretKey = "")
    {
        $length = strlen($url);
        if ($length == 0) {
            throw new \Exception("url is empty", 0);
        }
        $this->gatewayUrl = $url;
        $this->appkey = $appkey;
        $this->secretKey = $secretKey;
        $this->logLevel = Constants::$log_level_error;
    }

    protected function generateSign($apiName, $params)
    {
        foreach ($params as $key => $val) {
            $val = trim($val);
            if (empty($val) || $key == 'sign' || $key == 'access_token') {
                unset($params[$key]);
            }
        }
        ksort($params);
        $app_secret = $this->secretKey;
        $str = "";
        foreach ($params as $key => $val) {
            $str .= "{$key}{$val}";
        }
        $str = $apiName . $str;
        $stringToBeSigned = $app_secret . $str . $app_secret;
        return $this->hmac_sha256($stringToBeSigned, $this->secretKey);
    }


    function hmac_sha256($data, $key)
    {
        return hash_hmac('sha256', $data, $key);
    }

    public function curl_get($url, $apiFields = null, $headerFields = null, $returnUrl = false)
    {
        $ch = curl_init();

        foreach ($apiFields as $key => $value) {
            $url .= "&" . "$key=" . urlencode($value);
        }
        if ($returnUrl) {
            return ($url);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FAILONERROR, false);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

        if ($headerFields) {
            $headers = array();
            foreach ($headerFields as $key => $value) {
                $headers[] = "$key: $value";
            }
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            unset($headers);
        }

        if ($this->readTimeout) {
            curl_setopt($ch, CURLOPT_TIMEOUT, $this->readTimeout);
        }

        if ($this->connectTimeout) {
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
        }

        curl_setopt($ch, CURLOPT_USERAGENT, $this->sdkVersion);

        //https ignore ssl check ?
        if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }

        $output = curl_exec($ch);

        $errno = curl_errno($ch);

        if ($errno) {
            curl_close($ch);
            throw new \Exception($errno, 0);
        } else {
            $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if (200 !== $httpStatusCode) {
                throw new \Exception($output, $httpStatusCode);
            }
        }

        return $output;
    }

    public function curl_post($url, $postFields = null, $fileFields = null, $headerFields = null, $returnUrl = false)
    {
        if ($returnUrl) {
            $pathUrlInfo = parse_url($url);
            $query = $pathUrlInfo['query'];
            $queryArr = explode('&', $query);//转成数组
            $res = array();
            foreach ($queryArr as $k => $v) {
                $queryArr = explode('=', $v);
                $res[$queryArr[0]] = $queryArr[1];
            }
            $uri = $pathUrlInfo['scheme'] . "://" . $pathUrlInfo['host'] . $pathUrlInfo['path'];
            if (is_array($res) && is_array($postFields)) {
                $form_params = array_merge($res, $postFields);
            }
            return array('uri' => $uri, 'form_params' => $form_params);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FAILONERROR, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        if ($this->readTimeout) {
            curl_setopt($ch, CURLOPT_TIMEOUT, $this->readTimeout);
        }

        if ($this->connectTimeout) {
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
        }

        if ($headerFields) {
            $headers = array();
            foreach ($headerFields as $key => $value) {
                $headers[] = "$key: $value";
            }
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            unset($headers);
        }

        curl_setopt($ch, CURLOPT_USERAGENT, $this->sdkVersion);

        //https ignore ssl check ?
        if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }

//        $delimiter = '-------------' . uniqid();
//        $data = '';
//        if ($postFields != null) {
//            foreach ($postFields as $name => $content) {
//                $data .= "--" . $delimiter . "\r\n";
//                $data .= 'Content-Disposition: form-data; name="' . $name . '"';
//                $data .= "\r\n\r\n" . $content . "\r\n";
//            }
//            unset($name, $content);
//        }

//        if ($fileFields != null) {
//            foreach ($fileFields as $name => $file) {
//                $data .= "--" . $delimiter . "\r\n";
//                $data .= 'Content-Disposition: form-data; name="' . $name . '"; filename="' . $file['name'] . "\" \r\n";
//                $data .= 'Content-Type: ' . $file['type'] . "\r\n\r\n";
//                $data .= $file['content'] . "\r\n";
//            }
//            unset($name, $file);
//        }
//        $data .= "--" . $delimiter . "--";
//
//        curl_setopt($ch, CURLOPT_POST, true);
//        curl_setopt($ch, CURLOPT_HTTPHEADER,
//            array(
//                'Content-Type: multipart/form-data; boundary=' . $delimiter,
//                'Content-Length: ' . strlen($data)
//            )
//        );
//        CURLOPT_CUSTOMREQUEST => 'POST',
//          CURLOPT_POSTFIELDS =>'{
//            "order_id_list": [
//                "576461322015378144",
//                "576461311696996546"
//            ]
//        }',
//          CURLOPT_HTTPHEADER => array(
//                'Content-Type: application/json'
//            ),
//        ));

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields));

        $response = curl_exec($ch);
        unset($data);

        $errno = curl_errno($ch);
        if ($errno) {
            curl_close($ch);
            throw new \Exception($errno, 0);
        } else {
            $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if (200 !== $httpStatusCode) {
                throw new \Exception($response, $httpStatusCode);
            }
        }

        return $response;
    }

    public function execute(TikTokRequest $request, $accessToken = null, $shopId = null, $returnUrl = false)
    {
        $sysParams["timestamp"] = $this->msectime();
        $sysParams["app_key"] = $this->appkey;
        if (!empty($shopId)) $sysParams["shop_id"] = $shopId;
        $sysParams["access_token"] = $accessToken;

        $apiParams = $request->udfParams;

        $requestUrl = $this->gatewayUrl;

        if ($this->endWith($requestUrl, "/")) {
            $requestUrl = substr($requestUrl, 0, -1);
        }

        $requestUrl .= $request->apiName;
        $requestUrl .= '?';

        //dd(array_merge($apiParams, $sysParams));
        $sysParams["sign"] = $this->generateSign($request->apiName, $sysParams);
        foreach ($sysParams as $sysParamKey => $sysParamValue) $requestUrl .= "$sysParamKey=" . urlencode($sysParamValue) . "&";
        $requestUrl = substr($requestUrl, 0, -1);
        try {
            if ($request->httpMethod == 'POST') {
                $resp = $this->curl_post($requestUrl, $apiParams, $request->fileParams, $request->headerParams, $returnUrl);
                if ($returnUrl) {
                    return $resp;
                }
            } else {
                $resp = $this->curl_get($requestUrl, $apiParams, $request->headerParams, $returnUrl);
            }
        } catch (\Exception $e) {
            throw $e;
        }
        unset($apiParams);
        return $resp;
    }


    function msectime()
    {
        //list($msec, $sec) = explode(' ', microtime());
        return time();
    }

    function endWith($haystack, $needle)
    {
        $length = strlen($needle);
        if ($length == 0) {
            return false;
        }
        return (substr($haystack, -$length) === $needle);
    }

}
